package com.singfan.app.controller;

import com.singfan.app.controller.model.HttpModelConverter;
import com.singfan.app.controller.model.request.BarberAppointmentRequest;
import com.singfan.app.controller.model.request.BarberDetailRequest;
import com.singfan.app.controller.model.request.BarberListRequest;
import com.singfan.app.controller.model.request.BarberProductListRequest;
import com.singfan.app.controller.model.response.*;
import com.singfan.app.controller.model.response.partial.*;
import com.singfan.app.util.AppointmentUtil;
import com.singfan.app.util.RequestParamChecker;
import com.singfan.common.util.GPSUtil;
import com.singfan.core.component.CustomerTokenHolder;
import com.singfan.core.dao.database.config.ConfigDataManager;
import com.singfan.core.dao.database.model.*;
import com.singfan.core.dao.database.model.constant.AppointmentType;
import com.singfan.core.dao.database.model.constant.CollectType;
import com.singfan.core.dao.database.model.constant.FilterType;
import com.singfan.core.dao.database.model.constant.HairServiceType;
import com.singfan.core.service.BarberListResult;
import com.singfan.core.service.IShopService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * Author: hansonghe
 * Date: 2015-08-24 16:18
 * Desc:
 */
@Controller
public class BarberController extends SingFanControllerBase {
    @Autowired
    private IShopService shopService;

    @RequestMapping(value="/v1/barber/list", method= RequestMethod.POST)
    public void list(HttpServletRequest request, HttpServletResponse response){
        BarberListResponse result = new BarberListResponse();
        BarberListRequest barberListRequest = request2Bean(request, BarberListRequest.class);

        boolean checkResult = true;

        String ip = getIpAddress(request);
        String accessToken = barberListRequest.getAccessToken();
        int serviceType = barberListRequest.getServiceType();
        int listOrderType = barberListRequest.getListOrderType();
        String longitudeText = barberListRequest.getLongitude();
        String latitudeText = barberListRequest.getLatitude();
        int pageIndex = barberListRequest.getPageIndex();
        int pageSize = barberListRequest.getPageSize();
        boolean onlyMaster = barberListRequest.isOnlyMaster();
        int dayTime = barberListRequest.getDayTime();
        int clockTime = barberListRequest.getClockTime();

        if (!(HairServiceType.isHairServiceType(serviceType) || serviceType == 0)){
            checkResult = false;
        }
        else if(!(FilterType.isFilterType(listOrderType))){
            checkResult = false;
        }
        else if (!RequestParamChecker.checkLongitude(longitudeText)){
            checkResult = false;
        }
        else if (!RequestParamChecker.checkLatitude(latitudeText)){
            checkResult = false;
        }
        else if(!RequestParamChecker.checkPageIndexAndSize(pageIndex, pageSize)){
            checkResult = false;
        }
        else if (!((dayTime > -1 && RequestParamChecker.checkAppointmentDayTime(dayTime)) || dayTime <= -1)){
            checkResult = false;
        }

        double longitude = Double.parseDouble(longitudeText);
        double latitude = Double.parseDouble(latitudeText);

        if (checkResult){
            result.setResultCode(ResultCode.SUCCESS);
            BarberListResult barberListResult = barberService.findBarberList(barberListRequest.getServiceType(), barberListRequest.getListOrderType(), barberListRequest.getCityId(), barberListRequest.getBusinessCircleId(), longitude, latitude, barberListRequest.getPageIndex(), barberListRequest.getPageSize(), dayTime, clockTime, onlyMaster);
            List<Barber> barberList = barberListResult.getBarberList();
            result.setPageIndex(barberListResult.getPageIndex());
            List<BarberPartial> barberPartialList = new ArrayList<>(barberList.size());
            for (Barber barber : barberList){
                BarberPartial barberPartial = HttpModelConverter.barber2BarberPartial(barber);
                int distance = GPSUtil.getDistance(longitude, latitude, barber.getLongitude().doubleValue(), barber.getLatitude().doubleValue());
                barberPartial.setDistance(distance);

                barberPartialList.add(barberPartial);
            }
            if (barberListRequest.getListOrderType() == FilterType.DISTANCE) {
                java.util.Collections.sort(barberPartialList, new Comparator(){
                    @Override
                    public int compare(Object o1, Object o2) {
                        BarberPartial barberPartial1 = (BarberPartial)o1;
                        BarberPartial barberPartial2 = (BarberPartial)o2;
                        return barberPartial1.getDistance() - barberPartial2.getDistance();
                    }
                });
            }
            result.setBarberList(barberPartialList);

            traceLog.debug(String.format("BarberController.list() successful -> resultCode:%1$d, ip:%2$s, accessToken:%3$s, serviceType:%4$d, listOrderType:%5$d, longitude:%6$s, latitude:%7$s, pageIndex:%8$d, pageSize:%9$d, dayTime:%10$d, clockTime:%11$d, onlyMaster:%12$b", ResultCode.SUCCESS, ip, accessToken, serviceType, listOrderType, longitudeText, latitudeText, pageIndex, pageSize, dayTime, clockTime, onlyMaster));
        }
        else {
            result.setResultCode(ResultCode.REQUEST_PARAM_ERROR);

            traceLog.error(String.format("BarberController.list() error with REQUEST_PARAM_ERROR -> resultCode:%1$d, ip:%2$s, accessToken:%3$s, serviceType:%4$d, listOrderType:%5$d, longitude:%6$s, latitude:%7$s, pageIndex:%8$d, pageSize:%9$d, dayTime:%10$d, clockTime:%11$d, onlyMaster:%12$b", ResultCode.REQUEST_PARAM_ERROR, ip, accessToken, serviceType, listOrderType, longitudeText, latitudeText, pageIndex, pageSize, dayTime, clockTime, onlyMaster));
        }

        bean2Response(response, result);
    }

    @RequestMapping(value="/v1/barber/detail", method= RequestMethod.POST)
    public void detail(HttpServletRequest request, HttpServletResponse response){
        BarberDetailRequest barberDetailRequest = request2Bean(request, BarberDetailRequest.class);

        String ip = getIpAddress(request);
        long barberId = barberDetailRequest.getBarberID();
        String accessToken = barberDetailRequest.getAccessToken();
        String longitudeText = barberDetailRequest.getLongitude();
        String latitudeText = barberDetailRequest.getLatitude();

        boolean checkResult = true;

        if(barberId < 0){
            checkResult = false;
        }
        else if (!RequestParamChecker.checkLongitude(longitudeText)){
            checkResult = false;
        }
        else if (!RequestParamChecker.checkLatitude(latitudeText)){
            checkResult = false;
        }

        double longitude = Double.valueOf(longitudeText);
        double latitude = Double.valueOf(latitudeText);

        BarberDetailResponse barberDetailResponse = new BarberDetailResponse();
        if (checkResult){
            barberDetailResponse.setResultCode(ResultCode.SUCCESS);
            Barber barber = barberService.findBarber(barberId);
            barberDetailResponse.setBarberID(barber.getId());
            barberDetailResponse.setBarberAvatar(barber.getAvatar());
            barberDetailResponse.setBarberName(barber.getNickName());
            barberDetailResponse.setShopId(barber.getShopId());
            barberDetailResponse.setMasterShopName(barber.getMasterShopName());
            barberDetailResponse.setSlaveShopName(barber.getSlaveShopName());
            barberDetailResponse.setBarberTitle(ConfigDataManager.getInstance().getBarberPositionConfig(barber.getPositionId()).getPosition());
            int distance = GPSUtil.getDistance(longitude, latitude, barber.getLongitude().doubleValue(), barber.getLatitude().doubleValue());
            barberDetailResponse.setDistance(distance);
            barberDetailResponse.setOrderCount(barber.getOrderCount());
            barberDetailResponse.setGoodCommentCount(barber.getFavorableCommentCount());
            barberDetailResponse.setCommentCount(barber.getCommentCount());
            barberDetailResponse.setHonorIcon(barber.getHonor());
            LocationPartial locationPartial = new LocationPartial();
            locationPartial.setAddressText(barber.getAddress());
            locationPartial.setShopMasterName(barber.getMasterShopName());
            locationPartial.setShopSlaveName(barber.getSlaveShopName());
            locationPartial.setLongitude(String.valueOf(barber.getLongitude()));
            locationPartial.setLatitude(String.valueOf(barber.getLatitude()));
            barberDetailResponse.setShopLocation(locationPartial);
            Shop shop = shopService.findShop(barber.getShopId());
            if (shop != null){
                barberDetailResponse.setShopTelNum(shop.getContactNumber());
            }
            else {
                barberDetailResponse.setShopTelNum("");
            }
            long customerId = 0;
            CustomerToken customerToken = CustomerTokenHolder.getCurrentCustomerToken();
            if (customerToken != null){
                customerId = customerToken.getCustomerId();
            }

            if (customerId > 0){
                boolean isCollected = customerService.isCollected(customerId, barber.getId(), CollectType.BARBER);
                barberDetailResponse.setCollected(isCollected);
            }
            else {
                barberDetailResponse.setCollected(false);
            }

            List<ShopHairService> shopHairServiceList = shopService.selectShopHairServiceList(barber.getShopId());
            List<PriceMenuItemPartial> priceMenuItemPartialList = new ArrayList<>(shopHairServiceList.size());
            for (ShopHairService shopHairService : shopHairServiceList){
                PriceMenuItemPartial itemPartial = new PriceMenuItemPartial();

                itemPartial.setItemType(shopHairService.getServiceType());
                itemPartial.setItemID(shopHairService.getId());
                itemPartial.setItemName(shopHairService.getServiceName());
                itemPartial.setOriginalPrice(shopHairService.getOriginalPrice());
                itemPartial.setCurrentPrice(shopHairService.getRealPrice());

                if (shopHairService.getServiceType() == HairServiceType.HAIR_CUT){
                    if (barber.getHairCutRealPrice() > 0){
                        itemPartial.setOriginalPrice(barber.getHairCutOriginalPrice());
                        itemPartial.setCurrentPrice(barber.getHairCutRealPrice());
                        priceMenuItemPartialList.add(itemPartial);
                    }
                }
                else if (shopHairService.getServiceType() == HairServiceType.HAIR_MODELING){
                    if (barber.getHairModelingRealPrice() > 0){
                        itemPartial.setOriginalPrice(barber.getHairModelingOriginalPrice());
                        itemPartial.setCurrentPrice(barber.getHairModelingRealPrice());
                        priceMenuItemPartialList.add(itemPartial);
                    }
                }
                else{
                    priceMenuItemPartialList.add(itemPartial);
                }
            }
            barberDetailResponse.setPriceMenu(priceMenuItemPartialList);

            traceLog.debug(String.format("BarberController.detail() successful -> resultCode:%1$d, ip:%2$s, accessToken:%3$s, longitude:%4$s, latitude:%5$s", ResultCode.SUCCESS, ip, accessToken, longitudeText, latitudeText));
        }
        else {
            barberDetailResponse.setResultCode(ResultCode.REQUEST_PARAM_ERROR);

            traceLog.error(String.format("BarberController.detail() error with REQUEST_PARAM_ERROR -> resultCode:%1$d, ip:%2$s, accessToken:%3$s, longitude:%4$s, latitude:%5$s", ResultCode.REQUEST_PARAM_ERROR, ip, accessToken, longitudeText, latitudeText));
        }

        bean2Response(response, barberDetailResponse);
    }

    @RequestMapping(value="/v1/barber/product/list", method= RequestMethod.POST)
    public void productList(HttpServletRequest request, HttpServletResponse response){
        BarberProductListRequest barberProductListRequest = request2Bean(request, BarberProductListRequest.class);
        boolean checkResult = true;
        String ip = getIpAddress(request);
        String accessToken = barberProductListRequest.getAccessToken();
        long barberId = barberProductListRequest.getBarberID();
        int pageIndex = barberProductListRequest.getPageIndex();
        int pageSize = barberProductListRequest.getPageSize();

        if (barberId < 0){
            checkResult = false;
        }
        else if (!RequestParamChecker.checkPageIndexAndSize(pageIndex, pageSize)){
            checkResult = false;
        }

        BarberProductListResponse barberProductListResponse = new BarberProductListResponse();
        if (checkResult){
            barberProductListResponse.setResultCode(ResultCode.SUCCESS);
            if (barberProductListRequest.getPageIndex() == 0){
                barberProductListResponse.setNewList(true);
            }

            List<BarberHairstyle> barberHairstyleList = barberService.findBarberHairstyleList(barberId, pageIndex, pageSize);
            List<HairstylePartial> hairstyleProductList = new ArrayList<>(barberHairstyleList.size());
            for (BarberHairstyle barberHairstyle : barberHairstyleList){
                HairstylePartial hairstylePartial = HttpModelConverter.barberHairstyle2HairstylePartial(barberHairstyle);
                hairstyleProductList.add(hairstylePartial);
            }
            barberProductListResponse.setHairstyleProductList(hairstyleProductList);

            traceLog.debug(String.format("BarberController.productList() successful -> resultCode:%1$d, ip:%2$s, accessToken:%3$s, barberId:%4$d, pageIndex:%5$d, pageSize:%6$d", ResultCode.SUCCESS, ip, accessToken, barberId, pageIndex, pageSize));
        }
        else {
            barberProductListResponse.setResultCode(ResultCode.REQUEST_PARAM_ERROR);

            traceLog.error(String.format("BarberController.productList() error with REQUEST_PARAM_ERROR -> resultCode:%1$d, ip:%2$s, accessToken:%3$s, barberId:%4$d, pageIndex:%5$d, pageSize:%6$d", ResultCode.REQUEST_PARAM_ERROR, ip, accessToken, barberId, pageIndex, pageSize));
        }


        bean2Response(response, barberProductListResponse);
    }

    @RequestMapping(value="/v1/barber/appointment", method= RequestMethod.POST)
    public void appointment(HttpServletRequest request, HttpServletResponse response){
        BarberAppointmentResponse result = new BarberAppointmentResponse();
        BarberAppointmentRequest barberAppointmentRequest = request2Bean(request, BarberAppointmentRequest.class);

        String ip = getIpAddress(request);
        String accessToken = barberAppointmentRequest.getAccessToken();
        long barberId = barberAppointmentRequest.getBarberId();
        int dayTime = barberAppointmentRequest.getDayTime();

        CustomerToken customerToken = CustomerTokenHolder.getCurrentCustomerToken();
        if (barberId > 0){
            if (customerToken != null){
                if (RequestParamChecker.checkAppointmentDayTime(dayTime)){
                    List<BarberAppointment> appointmentList = barberService.findBarberAppointmentListByDayTime(barberId, dayTime);
                    List<AppointmentPartial> appointmentPartialList = getAppointmentPartialList(dayTime, appointmentList);
                    result.setAppointmentList(appointmentPartialList);

                    traceLog.debug(String.format("BarberController.appointment() successful -> resultCode:%1$d, ip:%2$s, accessToken:%3$s, barberId:%4$d, dayTime:%5$d", ResultCode.SUCCESS, ip, accessToken, barberId, dayTime));
                }
                else {
                    traceLog.error(String.format("BarberController.appointment() error with REQUEST_PARAM_ERROR -> resultCode:%1$d, ip:%2$s, accessToken:%3$s, barberId:%4$d, dayTime:%5$d", ResultCode.REQUEST_PARAM_ERROR, ip, accessToken, barberId, dayTime));
                }
            }
            else {
                result.setResultCode(ResultCode.ACCESS_TOKEN_ERROR);

                traceLog.error(String.format("BarberController.appointment() error with ACCESS_TOKEN_ERROR -> resultCode:%1$d, ip:%2$s, accessToken:%3$s, barberId:%4$d, dayTime:%5$d", ResultCode.ACCESS_TOKEN_EXPIRED, ip, accessToken, barberId, dayTime));
            }
        }
        else {
            result.setResultCode(ResultCode.REQUEST_PARAM_ERROR);

            traceLog.error(String.format("BarberController.appointment() error with REQUEST_PARAM_ERROR -> resultCode:%1$d, ip:%2$s, accessToken:%3$s, barberId:%4$d, dayTime:%5$d", ResultCode.ACCESS_TOKEN_EXPIRED, ip, accessToken, barberId, dayTime));
        }

        bean2Response(response, result);
    }

    private List<AppointmentPartial> getAppointmentPartialList(int dayTime, List<BarberAppointment> appointmentList) {
        int todayTime = AppointmentUtil.getTodayTime();
        Set<Integer> bookedSet = new HashSet<>();
        Set<Integer> noBookSet = new HashSet<>();
        for (BarberAppointment barberAppointment : appointmentList){
            if (barberAppointment.getCustomerId() > 0){
                bookedSet.add(barberAppointment.getAppointmentClock());
            }
            else {
                noBookSet.add(barberAppointment.getAppointmentClock());
            }
        }
        int nowClock = AppointmentUtil.getNowClock();
        List<AppointmentPartial> appointmentPartialList = new ArrayList<>();
        List<Integer> keySet = AppointmentUtil.createOneDayAppointmentList();
        for (Integer clock : keySet) {
            AppointmentPartial appointmentPartial = new AppointmentPartial();
            appointmentPartial.setClock(clock);
            if (dayTime == todayTime){
                if (clock > nowClock){
                    appointmentPartial.setStatus(AppointmentType.BOOKING);
                }
                else {
                    appointmentPartial.setStatus(AppointmentType.EXPIRED);
                }
            }
            else if (dayTime > todayTime){
                appointmentPartial.setStatus(AppointmentType.BOOKING);
            }
            else {
                appointmentPartial.setStatus(AppointmentType.EXPIRED);
            }


            if (bookedSet.contains(clock)){
                appointmentPartial.setStatus(AppointmentType.BOOKED);
            }
            else if (noBookSet.contains(clock)){
                appointmentPartial.setStatus(AppointmentType.NO_BOOK);
            }

            appointmentPartialList.add(appointmentPartial);
        }
        return appointmentPartialList;
    }
}
